package face.pay.sharing.biz;

import com.alibaba.fastjson.JSON;
import com.face.pay.WxApiConfig;
import com.github.wxpay.sdk.WXPayConstants;
import com.github.wxpay.sdk.WXPayRequest;
import com.github.wxpay.sdk.WXPayUtil;
import face.pay.dao.CpnCardMessageDao;
import face.pay.dao.SharingOrderInfoDao;
import face.pay.entity.*;
import face.pay.util.FaceStringBuffer;
import face.pay.util.MathUtil;
import face.pay.vo.VSharingAccount;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;

/**
 * 分账
 */
@Service
@Slf4j
public class SharingOrderBiz {

    @Autowired
    SharingQueryBiz sharingQueryBiz;

    @Autowired
    CpnCardMessageDao cpnCardMessageDao;


    private final static   String domain    = "api.mch.weixin.qq.com";

    /**
     * secapi/pay/profitsharing
     */
    private final static   String urlSuffix = "/secapi/pay/profitsharing";

    @Autowired
    private SharingOrderInfoDao sharingOrderInfoDao;
    /**
     *
     * @param wxApiConfig
     * @param orderInfo
     * @param cpnCardDetailInfo
     * @return
     */
    public Boolean sharing(WxApiConfig wxApiConfig, OrderInfo orderInfo, EnterpriseInfo enterpriseInfo, CpnCardDetailInfo cpnCardDetailInfo, Map<String,VSharingAccount> map){

        try {
            log.error("订单分账");
            Double  rate =enterpriseInfo.getWxFinalRate()==null?new Double(0):enterpriseInfo.getWxFinalRate();

            Double enterprise_rate =   new BigDecimal(new Double(rate).toString()).divide(new BigDecimal("100")).doubleValue();
            log.error("商家当前微信签约费率："+enterprise_rate);

            Long actFee = orderInfo.getActFee();
            Long totalFee = orderInfo.getTotalFee();
            /**
             * 用户享受优惠金额
             */
            Long userDisMoney = totalFee-actFee;

            log.error("总金额： totalFee："+totalFee);
            log.error("应总金额： actFee："+actFee);
            log.error("用户享受优惠金额： userDisMoney："+userDisMoney);

            /**
             * 优惠券当时 商家服务费
             */
            Double mchFee = cpnCardDetailInfo.getMchFee();

            log.error("优惠券当时 商家服务费率： mchFee："+mchFee);
            Long   serviceMoney =  MathUtil.profit(totalFee,mchFee);
            log.error("本笔订单商家需要扣除的服务费： serviceMoney："+serviceMoney);


            /**
             * oem 服务费率
             */
            Double oemFee      =  cpnCardDetailInfo.getOemFee();

            log.error("本次订单 oem 利润 利率"+oemFee);

            Long wxMoney = MathUtil.profit(actFee,enterprise_rate);

            log.error("本次订单 微信手续费"+wxMoney);

            /**
             * oem 应该收取的服务费
             */
            Long   oemFeeMoney =  MathUtil.profit(totalFee,oemFee);

            log.error("本次订单 oem 应得 金额:"+oemFeeMoney);

            oemFeeMoney = oemFeeMoney-wxMoney;

            log.error("本次订单 oem 扣除微信手续费后 金额: "+oemFeeMoney);


            /**
             * 制券平台 服务费
             */
            Double cpnFee      =  cpnCardDetailInfo.getCpnFee();
            log.info("本次订单 cpn 利润 利率: "+cpnFee);
            Long   cpnFeeMoney =  MathUtil.profit(totalFee,cpnFee);
            log.info("本次订单 cpn 应得到金额:"+cpnFeeMoney);


            Long actServiceFeeMoney = serviceMoney-userDisMoney;
            log.info("本次消费 扣除用户优惠后 实际总利润为:"+actServiceFeeMoney);

            /**
             * 该优惠券 当时 商家给平台结算价格
             */


            Double marketFee = cpnCardDetailInfo.getMarketFee()==null?new Double(0):cpnCardDetailInfo.getMarketFee();
            log.error("本次订单 market 结算费率:"+marketFee);

            Double coFee =      MathUtil.add(cpnFee,oemFee);
            Double mFee = MathUtil.sub(mchFee,coFee);
            /**
             *商家为受限制情况下 利润
             *  总金额 *（oem+cpm）-折扣
             */
            Long   marketFeeMoney =  MathUtil.profit(totalFee,mFee);
            marketFeeMoney = marketFeeMoney-userDisMoney;


            log.error("本次订单 marketFeeMoney:"+marketFeeMoney);

            log.info("计算是否结算有差额");
            /**
             * 计算是否有剩余的利润没有分掉
             */
            Double marlet_dif_fee = MathUtil.sub(mchFee, MathUtil.add(cpnFee,oemFee));
            marlet_dif_fee= MathUtil.sub(marlet_dif_fee,marketFee);
            log.info("marlet_dif_fee:"+marlet_dif_fee);
            /**
             * 计算 商家 对（cpn+oem） 和  markey 之间的差额
             *  商家对cpn+oem  规则为 服务费-cpnFee-oemFee 对外结算价
             * 商家对 maeket 则考虑渠道前置
             * 两者之间剩出的利润 归 cpn
             *
             */
            Long market_dif_money  = new Long(0);

            if(marlet_dif_fee>0){

                market_dif_money = MathUtil.profit(totalFee,marlet_dif_fee);

                marketFeeMoney = MathUtil.sub(marketFeeMoney,market_dif_money);
                log.error("剩下金额为："+market_dif_money);
            }



            /**
              * 留给market 平台的费用
              */
            log.info("总金额：   totalFee："+totalFee);
            log.info("应总金额： actFee："+actFee);
            log.info("投放平台利润:"+marketFeeMoney);
            log.info("OEM平台利润 :"+oemFeeMoney);
            log.info("CPN平台利润:"+cpnFeeMoney);

            if(market_dif_money.compareTo(new Long(0))==1){
                log.error("将尚未分配的金额 分到cpn "+market_dif_money);
                cpnFeeMoney =  MathUtil.add(cpnFeeMoney,market_dif_money);
                log.error("CPN平台最终利润:"+cpnFeeMoney);
            }

            Long actProfitMoney =MathUtil.add(marketFeeMoney, MathUtil.add(cpnFeeMoney,oemFeeMoney));
            log.info("真正分出总金额："+actProfitMoney);

            /**
             * actProfitMoney<serviceMoney (商家服务费 -折扣)
             */

            if(actProfitMoney.compareTo(serviceMoney)<=1){
                log.info("分账验金额 证正确");

                orderInfo.setServiceFee(actProfitMoney);
                orderInfo.setDiscountMoney(userDisMoney);

                Long  actInnerFee =   MathUtil.sub(actFee,actProfitMoney);
                log.info("商家实际到账："+actInnerFee);

                orderInfo.setActInnerFee(actInnerFee);
                log.error("商家实际到账金额： actInnerFee："+actInnerFee);

                /**
                 * 参与分账的 金额有
                 * marketFeeMoney
                 * oemFeeMoney
                 * cpnFeeMoney
                 */

                log.info("添加 分账对象 MARKET");
                List<VSharingAccount> sharingAccounts =  new ArrayList<>();
                VSharingAccount marketAccount =  map.get("MARKET");

                if(marketAccount!=null){
                    marketAccount.setMoney(marketFeeMoney);
                    sharingAccounts.add(marketAccount);

                    /**
                     * 插入 消息发送
                     */
                }else {
                    log.info("分账对象 MARKET 不存在");
                }

                log.info("添加 分账对象 OEM");
                VSharingAccount oemAccount     =  map.get("OEM");
                if(oemAccount!=null){
                    oemAccount.setMoney(oemFeeMoney);
                    sharingAccounts.add(oemAccount);
                }else {
                    log.info("分账对象 OEM 不存在");
                }

                log.info("添加 分账对象 CPN");
                VSharingAccount cpnAccount     =  map.get("CPN");
                if(cpnAccount!=null){
                    cpnAccount.setMoney(cpnFeeMoney);
                    sharingAccounts.add(cpnAccount);
                }else {
                    log.info("分账对象 CPN 不存在");
                }
                /**
                 * 为了避免触发微信接口频率限制
                 * 走单次分账接口
                 */
                Integer accountSize = sharingAccounts.size();
                log.info("总共分账对象数量为："+accountSize);
               return   this.sharingAccount(wxApiConfig,orderInfo,enterpriseInfo,sharingAccounts,cpnCardDetailInfo);
            }else{
              log.error("分账金额错误超限");
            }

        }catch (Exception e){
            log.error("分账异常");
        }
        return  false;
    };


    public Boolean sharingAccount(WxApiConfig wxApiConfig, OrderInfo orderInfo, EnterpriseInfo enterpriseInfo, List<VSharingAccount> sharingAccounts,CpnCardDetailInfo cpnCardDetailInfo){

        log.info("开始分账");
        Boolean success = false;
        List<SharingOrderInfo> sharingOrderInfos = new ArrayList<>();

        try{

            String sharingMessage = null;

            Long orderId = orderInfo.getId();

            String appId = wxApiConfig.getAppID();
            String apiKey = wxApiConfig.getKey();
            String mchId = wxApiConfig.getMchID();

            String tradeNo = orderInfo.getTradeNo();

            String subMchId = enterpriseInfo.getWxSubMchId();

            WXPayRequest wxPayRequest = new WXPayRequest(wxApiConfig);

            String nonce_str = WXPayUtil.generateNonceStr();

            Map<String, String> map = new HashMap<>();
            map.put("mch_id", mchId);
            map.put("nonce_str", nonce_str);
            map.put("sub_mch_id", subMchId);
            map.put("appid", appId);
            map.put("transaction_id", tradeNo);

            String out_order_no =  orderInfo.getSharingNo();

            map.put("out_order_no", out_order_no);

            List<Map<String, Object>> receivers = new ArrayList<>();

            orderInfo.setSharingNo(out_order_no);


            for(VSharingAccount sharingAccount:sharingAccounts){
                if(sharingAccount!=null){
                    Integer status = sharingAccount.getStatus();

                    SharingOrderInfo sharingOrderInfo =  new SharingOrderInfo(
                            orderInfo.getTradeNo(),
                            orderInfo.getId(),
                            sharingAccount.getMoney(),
                            sharingAccount.getId(),
                            sharingAccount.getAccount(),
                            sharingAccount.getAccountName(),
                            sharingAccount.getAccountType()
                    );

                    sharingOrderInfo.setOutOrderNo(out_order_no);
                    sharingOrderInfo.setType(sharingAccount.getType());
                    sharingOrderInfo.setCardDetailId(cpnCardDetailInfo.getId());
                    sharingOrderInfo.setMarketId(cpnCardDetailInfo.getMarketId());
                    sharingOrderInfo.setBizCode(cpnCardDetailInfo.getBizCode());

                    if(new Integer(1).equals(status)) {
                        if(sharingAccount.getMoney()>0){

                            Map<String, Object> receiver = new HashMap<>();
                            receiver.put("type", sharingOrderInfo.getAccountType());
                            receiver.put("account", sharingOrderInfo.getAccount());
                            receiver.put("amount", sharingOrderInfo.getMoney());
                            receiver.put("description", "优惠券核销服务费");
                            receivers.add(receiver);

                        }else {
                            sharingOrderInfo.setStatus(-2);
                            sharingOrderInfo.setMessage("分账金额不对");
                            log.info("分账失败");
                        }
                    }else {
                        sharingOrderInfo.setStatus(0);
                        sharingOrderInfo.setMessage("分账关系错误 分账失败");
                        log.info("分账失败");
                    }
                    sharingOrderInfos.add(sharingOrderInfo);
                }

            }

            String receiversJson = JSON.toJSONString(receivers);

            map.put("receivers", receiversJson);

            String xml = WXPayUtil.generateSignedXml(map, apiKey, WXPayConstants.SignType.HMACSHA256);
            log.info("发送请求 " + xml);

            String result = wxPayRequest.requestOnce(domain, urlSuffix, xml, true);
            log.info("返回结果 " + result);
            Map<String, String> resultMap = WXPayUtil.xmlToMap(result);

            Boolean isSuccess = WXPayUtil.isSuccess(resultMap);

            if(isSuccess){
                log.info("分账成功");
                success =  true;
                orderInfo.setSharing(1);
                orderInfo.setSharingNo("分账成功'");
                sharingMessage="分账成功";

            }else {
                orderInfo.setSharing(-1);

                String return_code  = resultMap.get("return_msg");

                String return_msg  = resultMap.get("return_msg");
                FaceStringBuffer stringBuffer = new FaceStringBuffer(return_msg);
                String err_code_des  = resultMap.get("err_code_des");
                stringBuffer.add(err_code_des);
                sharingMessage = stringBuffer.toString();
                orderInfo.setSharingMessage(sharingMessage);

                log.info("分账失败");
            }

            if(sharingOrderInfos.size()>0){
                setResult(success,sharingMessage,sharingOrderInfos);
                this.sharingOrderInfoDao.insertBatch(sharingOrderInfos);
            }

        }catch (Exception e){
            success =  false;
            log.error("分账异常",e);
        }
        return  success;

    }

    public  void setResult(Boolean isSuccess,String sharingMessage,List<SharingOrderInfo> list){
        for(SharingOrderInfo sharingOrderInfo: list){
            String ms = sharingOrderInfo.getMessage();

            FaceStringBuffer msg = new FaceStringBuffer(ms);
            msg.add(sharingMessage);

            sharingOrderInfo.setMessage(msg.toString());
            if(isSuccess){
                sharingOrderInfo.setStatus(1);
            }else{
                sharingOrderInfo.setStatus(-1);

            }

        }

    }

}
